package com.s.core.root;

import com.s.S;
import com.s.core.persist.CoreData;
import com.google.common.collect.Maps;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhangjiangnan
 */
@Data
@Slf4j
public class Ad {
    private static volatile Ad me;

    public static Ad me() {
        if (me == null) {
            synchronized (Ad.class) {
                if (me == null) {
                    me = new Ad();
                }
            }
        }
        return me;
    }

    private List<D> dList;
    private List<Basic> basicList;

    private Map<String, Map<String, D>> codeDateDailyMap;
    private Map<String, Map<String, D>> dateCodeDailyMap;
    private Map<String, List<D>> codeDailyListMap;
    private Map<String, List<D>> dateDailyListMap;
    private Map<String, Integer> datePos1Total;
    private List<String> dateList;

    private Ad() {
        long l = System.currentTimeMillis();
        CoreData coreData = S.persistService.load();
        log.info("load done {}", System.currentTimeMillis() - l);

        basicList = coreData.getBasicList();
        dList = coreData.getDList();

        parse1();
        parse2();
    }

    public void parse1() {
        codeDateDailyMap = dList.stream().collect(Collectors.groupingBy(D::getCode, Collectors.toMap(D::getDate, d -> d)));
        dateCodeDailyMap = dList.stream().collect(Collectors.groupingBy(D::getDate, Collectors.toMap(D::getCode, d -> d)));
        codeDailyListMap = dList.stream().collect(Collectors.groupingBy(D::getCode));
        dateDailyListMap = dList.stream().collect(Collectors.groupingBy(D::getDate));
        dateList = new ArrayList<>(dateDailyListMap.keySet());
        dateList.sort(Comparator.reverseOrder());
    }

    public void parse2() {
        datePos1Total = Maps.newHashMapWithExpectedSize(dateDailyListMap.keySet().size());
        dateDailyListMap.keySet().forEach(date -> {
            datePos1Total.put(date, (int) dateDailyListMap.get(date).stream().filter(d -> d.getPos1() != 0).count());
        });
    }


    public List<String> getCodes() {
        return basicList.stream().map(Basic::getCode).collect(Collectors.toList());
    }

    public Basic getBasicByCode(String code) {
        return basicList.stream().filter(basic -> basic.getCode().equals(code)).findFirst().orElse(null);
    }

    public void addBasic(String code, String name) {
        Basic basic = new Basic();
        basic.setCode(code);
        basic.setName(name);
        basicList.add(basic);
    }

    public void delBasic(String code) {
        dList.removeIf(d -> d.getCode().equals(code));
        basicList.removeIf(basic -> basic.getCode().equals(code));
    }

    public void renameBasic(String code, String name) {
        getBasicByCode(code).setName(name);
    }

    public String bDate(String date, int offset) {
        int index = dateList.indexOf(date);
        if (index == -1) {
            throw new RuntimeException();
        }
        if (index + offset >= dateList.size()) {
            return null;
        }
        return dateList.get(index + offset);
    }

    public String preDate(String date) {
        for (int i = 0; i < dateList.size(); i++) {
            if (dateList.get(i).equals(date) && i + 1 < dateList.size()) {
                return dateList.get(i + 1);
            }
        }
        return date;
    }

    public String nextDate(String date) {
        for (int i = 0; i < dateList.size(); i++) {
            if (dateList.get(i).equals(date) && i - 1 >= 0) {
                return dateList.get(i - 1);
            }
        }
        return date;
    }

    public void addDaily(D d) {
        dList.add(0, d);
    }

    public void removeDate(String delDate) {
        String date = delDate == null ? dateList.get(dateList.size() - 1) : delDate;
        dList.removeIf(d -> d.getDate().equals(date));
    }

    public D getDaily(String date, String code) {
        if (date == null) {
            return null;
        }
        if (dateCodeDailyMap != null && dateCodeDailyMap.get(date) != null) {
            return dateCodeDailyMap.get(date).get(code);
        }
        return null;
    }
}
